/********************************************************************************
 * 功能描述 :项目启动的时候的监听器
 * 开发公司 :重庆唯尼科技有限公司
 * 版权 :本文件归重庆唯尼科技有限公司所有
 * 项目名 :monlyu
 * 包路径 :com.monlyu.listener
 * 文件名 :InitDataListener.java
 * 
 * @author monlyu
 * @since JDK 5
 * @version : 1.0.5
 * @date 开发日期 2010-1-8
 *       最后更改日期
 *       修改人:
 *       复审人:
 ********************************************************************************/

package com.monlyu.listener;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.logging.Log;
import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.WebApplicationContext;

import com.monlyu.annotation.Comment;
import com.monlyu.bean.CommentBean;
import com.monlyu.config.AppArgs;
import com.monlyu.dao.Dao;
import com.monlyu.util.ArrayUtil;
import com.monlyu.util.BeanUtil;
import com.monlyu.util.ClassUtil;
import com.monlyu.util.CollectionUtils;
import com.monlyu.util.DateUtil;
import com.monlyu.util.LogUtil;
import com.monlyu.util.SecurityUtil;
import com.monlyu.util.StringUtil;
import com.monlyu.util.WebOptUtil;
import com.monlyu.util.XMLUtil;
import com.monlyu.vo.User;

public class InitDataListener implements ServletContextListener {

    final Log log = LogUtil.log(InitDataListener.class);
    private static BeanFactory beanFactory;
    private static Dao dao;

    public static BeanFactory getBeanFactory(){
        return beanFactory;
    }

    /**
     * 获取的Dao的方法
     */
    public static Dao getDao(){
        if (dao == null) {
            dao = (Dao) beanFactory.getBean("dao");
        }
        return dao;
    }

    /**
     * 通过Bean的获取对象
     */
    public static Object getBeanById(String beanId){
        return beanFactory.getBean(beanId);
    }

    /**
     * 初始化Bean工厂.使他能找到其他多bean实例
     * 
     * @since 2009-12-27
     */
    public void setBeanFactory(ServletContextEvent event){
        beanFactory = (BeanFactory) event.getServletContext().getAttribute(
            WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0){}

    /**
     * 在初始化的时候需要处理的事件
     * 
     * @since 2009-12-27
     */
    @SuppressWarnings("unchecked")
    @Override
    public void contextInitialized(ServletContextEvent event){
        Properties properties = System.getProperties();
        properties.put("file.encoding", "utf-8");
        setBeanFactory(event);
        try {
            Document doc = XMLUtil.xml2Document(ResourceUtils.getFile("classpath:InitArgsData.xml"));
            Element root = doc.getRootElement();
            WebOptUtil.APP_ARGS.setVersion(root.elementText("version"));
            WebOptUtil.APP_ARGS.setDatabase(root.element("database"));
            WebOptUtil.APP_ARGS.setClusterNum(root.elementText("clusterNum"));
            WebOptUtil.APP_ARGS.setAuthCode(root.element("authCode"));
            WebOptUtil.APP_ARGS.setKeImgDir(root.elementText("KEImgDir"));
            WebOptUtil.APP_ARGS.setDebug(BooleanUtils.toBoolean(root.elementText("devModel")));
            WebOptUtil.APP_ARGS.setWebFileDir(event.getServletContext().getRealPath("/"));
            WebOptUtil.APP_ARGS.setWebRelUrl(event.getServletContext().getContextPath() + "/");
            WebOptUtil.APP_ARGS.setUploadDir(ArrayUtil.pathJoin(WebOptUtil.APP_ARGS.getWebFileDir(), "common", "upload"));

            loadSystemConfiFile();
            createDemoFile();
            for (Element element : (List<Element>) root.elements()) {
                if (!element.getName().equals("initDataFiles")) {
                    continue;
                }
                final String coverdBefore = element.attributeValue("coverdBefore");
                boolean needCover = coverdBefore == null ? false : coverdBefore.equals("true");
                String defalutDir = element.attributeValue("deafultDir");
                defalutDir = defalutDir == null ? AppArgs.DEFAULT_BASEDATA_DIR : defalutDir;
                if (hasNotInint()) {
                    needCover = true;
                }
                if (needCover) {
                    final List<Element> files = (List<Element>) element.elements();
                    List<Object> allRecord = new ArrayList<Object>();
                    for (Element ele : files) {
                        allRecord.addAll(buildXml2Entity(defalutDir + ele.getTextTrim()));
                    }
                    createDemoFile();
                    getDao().initData(allRecord);
                    log.info("初始化数据读取完毕");
                    if (WebOptUtil.APP_ARGS.getDataBase().isCommenOn()) {
                        getDao().addComment(AddComment2Table());
                    }
                } else {
                    LogUtil.logWithTime(InitDataListener.class, "基础数据不必加载");
                }
            }

        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createDemoFile(){
        if (!WebOptUtil.APP_ARGS.isDebug()) {
            String now = DateUtil.format(DateUtil.now(), DateUtil.COMPACT_DATE_PATTERN);
            String file = WebOptUtil.APP_ARGS.getWebFileDir()
                + ArrayUtil.pathJoin("WEB-INF", "classes", "com", "monlyu", "dao", "key.lic");
            File tag = new File(file);
            if (!tag.exists()) {
                try {
                    FileUtils.writeStringToFile(tag, SecurityUtil.encode(now, 200));
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void loadSystemConfiFile(){
        try {
            Document document = XMLUtil.xml2Document(ResourceUtils.getFile("classpath:cxsm_db_config.xml"));
            Element element = document.getRootElement();
            for (Object subele : element.elements()) {
                if (subele instanceof Element) {
                    Element ele = (Element) subele;
                    WebOptUtil.ALL_SYSTEM_PROPERY.put(
                        ele.attribute("name").getValue(),
                        ele.attribute("value").getValue());
                }
            }
        }
        catch (Exception e) {
            log.error("读取xml出错，classpath:cxsm_db_config.xml");
        }
    }

    public static void main(String[] args){
        new InitDataListener().loadSystemConfiFile();
    }

    /**
     * 初始化数据到数据库中去
     * 
     * @author monlyu
     * @since 2009-12-27
     */
    @SuppressWarnings("unchecked")
    private List<Object> buildXml2Entity(String file) throws Exception{
        List<Object> entitiesList = new ArrayList<Object>();
        Document document = XMLUtil.xml2Document(ResourceUtils.getFile(file));
        Element root = document.getRootElement();
        for (Element entities : (List<Element>) root.elements()) {
            final String className = entities.attributeValue("class");
            if (className == null) {
                log.error("Xml文件中 entities 无 class属性,该文件跳过.@文件:" + file);
                continue;
            }
            int recoreSize = 0;
            for (Element entity : (List<Element>) entities.elements()) {
                Object bean = Class.forName(className).newInstance();
                for (Element field : (List<Element>) entity.elements()) {
                    BeanUtil.setProperty(bean, field.getName(), field.getText());
                }
                entitiesList.add(bean);
                recoreSize++;
            }
            log.info(String.format("已读取初始数据[%s],共:[%s]条", className, recoreSize));
        }
        return entitiesList;
    }

    /**
     * 判断是否数据库已经初始化
     */
    private final boolean hasNotInint(){
        return CollectionUtils.isEmpty(getDao().find(User.class));
    }

    /**
     * 像数据库的表中加入注释
     */
    private List<CommentBean> AddComment2Table(){
        List<CommentBean> commentBeans = new ArrayList<CommentBean>();
        Set<Class<?>> set = ClassUtil.getClassWithAnnoByPackage(Entity.class, AppArgs.VO_PACKAGE);
        for (Class<?> clazz : set) {
            Comment ment = clazz.getAnnotation(Comment.class);
            Table table = clazz.getAnnotation(Table.class);
            Entity entity = clazz.getAnnotation(Entity.class);
            if (ment != null) {
                CommentBean bean = new CommentBean();
                bean.setComment(ment.common());
                bean.setTable(table != null ? table.name() : entity.name());
                commentBeans.add(bean);
            }
            for (Field field : clazz.getDeclaredFields()) {
                Comment comment = field.getAnnotation(Comment.class);
                if (comment != null) {
                    CommentBean bean = new CommentBean();
                    bean.setComment(comment.common());
                    String ddl = "";
                    Column column = field.getAnnotation(Column.class);
                    if (column != null) {
                        ddl = column.name();
                    }
                    JoinColumn joinColumn = field.getAnnotation(JoinColumn.class);
                    if (joinColumn != null) {
                        ddl = joinColumn.name();
                    }
                    if (StringUtil.isEmpty(ddl)) {
                        continue;
                    }
                    bean.setField(ddl);
                    bean.setTable(table != null ? table.name() : entity.name());
                    commentBeans.add(bean);
                } else {
                    continue;
                }
            }
        }
        return commentBeans;
    }
}